﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib.BitArray;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Combinatorics;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;
using alib.String;

namespace agree.transfer_prototype
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TransferQueue : ObservableQueue<xfer_hyp>, IIdentity
	{
		public TransferQueue(TransferExecutor tex, Action<xfer_hyp> submit)
		{
			this.tex = tex;
			this.submit = submit;

			base.CollectionChanged += (o, e) => ((TransferQueue)o).q_change(e.Action);
		}

		readonly TransferExecutor tex;
		readonly Action<xfer_hyp> submit;

		void q_change(NotifyCollectionChangedAction action)
		{
			if (!tex.f_stop && action == NotifyCollectionChangedAction.Add)
				submit(Dequeue());
		}

		public IIdentity Trace { get { return tex; } }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct InpRulRelPair
	{
		public inp_rel inp;
		public rule_rel rul;
		public override String ToString()
		{
			return String.Format("{0}  -  {1}", inp, rul);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct RuleApplication : IEquatable<RuleApplication>
	{
		public rule rule;
		public int[] rg_inp_rel_ix;

		public bool Equals(RuleApplication other)
		{
			if (rule == null)
				return other.rule == null;
			int c;
			if (rule != other.rule || (c = rg_inp_rel_ix.Length) != other.rg_inp_rel_ix.Length)
				return false;
			for (int i = 0; i < c; i++)
				if (rg_inp_rel_ix[i] != other.rg_inp_rel_ix[i])
					return false;
			return true;
		}
		public override bool Equals(object obj)
		{
			return obj is RuleApplication && Equals((RuleApplication)obj);
		}
		public override int GetHashCode()
		{
			if (rule == null)
				return 0;
			int h = rule.GetHashCode();
			for (int i = 0; i < rg_inp_rel_ix.Length; i++)
			{
				int j = (rg_inp_rel_ix[i] + 1) << (i + 1);
				h ^= (h << j) ^ (h >> (32 - j));
			}
			return h;
		}
		public override String ToString()
		{
			if (rule == null)
				return "(null rule)";
			return String.Format("{0}[{1}]", rule.Name, rg_inp_rel_ix.StringJoin(","));
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public static class __xfer_ext
	{
		public static bool Subsumes(this type_base super, type_base sub)
		{
			if (super == null || super.Type == sub.Type)
				return true;

			var glb = Unify(super, sub);
			return glb != null && glb.Type == sub.Type;
		}

		public static type_base Unify(this type_base a, type_base b)
		{
			if (a == b || a == null)
				return b;
			if (b == null)
				return a;

			String ta, tb;
			int q;
			if ((q = String.CompareOrdinal(ta = a.Type, tb = b.Type)) == 0)
				return a;
#if true
			return null;
#else
			if (a is Var || b is Var)
				return null;

			if (q < 0)
				return new type(ta + new String('=', Math.Max(0, tb.Length - ta.Length)));
			if (q > 0)
				return new type(tb + new String('=', Math.Max(0, ta.Length - tb.Length)));

			return a;
#endif
		}

		public static void show_rels(this IReadOnlyList<rel_base> _this, System.IO.TextWriter tw)
		{
		}
	}


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary> display helper </summary>
	[DebuggerDisplay("{ToString(),nq}")]
	public class _inp_refs : List<NodePtr>
	{
		public override String ToString()
		{
			return this[0].node_type.ToString() + ": { " + this.Select(np => np.RelFeatInf).StringJoin(";  ") + " }";
		}
	};

	public sealed class arrow_rel : rel_base
	{
		static arrow_rel()
		{
			Instance = new arrow_rel();
		}
		public static rel_base Instance;
		arrow_rel() : base(null) { }
		public override string RelTypeName { get { return ""; } }
		public override int MaxWidth { get { return 1; } }
	}

	public static class fake
	{
		public static input_mrs get_input()
		{
			var mrs = new __input_mrs();
			new inp_rel(mrs) { LBL = "h1", PRED = "_rain_n_1_rel", ARG0 = "x1" }; // ฝน
			new inp_rel(mrs) { LBL = "h2", PRED = "exist_q_rel", ARG0 = "x1" };
			new inp_rel(mrs) { LBL = "h3", PRED = "_fall_v_1_rel", ARG0 = "e1", ARG1 = "x1" }; // ตก
			return mrs;
		}


		public static rule[] get_rules()
		{
			var rules = new rule[5];
			int i = 0;
			rule r;

			rules[i++] = r = new rule("its_raining_rule");
			new rule_src_rel(r) { PRED = "exist_q_rel", ARG0 = "x1" };
			new rule_src_rel(r) { PRED = "_fall_v_1_rel", ARG0 = "e1", ARG1 = "x1" };	// ตก
			new rule_src_rel(r) { PRED = "_rain_n_1_rel", ARG0 = "x1" };	// ฝน
			new rule_tgt_rel(r) { PRED = "_rain_v_1_rel", ARG0 = "e1" };

			rules[i++] = r = new rule("lbl_wiring_rule");
			new rule_src_rel(r) { LBL = "h1" };
			new rule_tgt_rel(r) { LBL = "h1" };

			rules[i++] = r = new rule("arg0_x_wiring_rule");
			new rule_src_rel(r) { ARG0 = "x1" };
			new rule_tgt_rel(r) { ARG0 = "x1" };

			rules[i++] = r = new rule("arg0_e_wiring_rule");
			new rule_src_rel(r) { ARG0 = "e1" };
			new rule_tgt_rel(r) { ARG0 = "e1" };

			rules[i++] = r = new rule("arg1_wiring_rule");
			new rule_src_rel(r) { ARG1 = "x1" };
			new rule_tgt_rel(r) { ARG1 = "x1" };

			return rules;
		}
	}
}